package com.ossjk.core.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ObjectUtil {

	private static final String SETTER_PREFIX = "set";

	private static final String GETTER_PREFIX = "get";

	private static Logger log = LoggerFactory.getLogger(ObjectUtil.class);

	/**
	 * 获取父类
	 * 
	 * @param clazz
	 * @return
	 */
	public static Class getSuperClass(Class<?> clazz) {
		if (!CommonUtil.isBlank(clazz)) {
			return clazz.getSuperclass();
		}
		return null;
	}

	/**
	 * 获取父类
	 * 
	 * @param obj
	 * @return
	 */
	public static Class getSuperClass(Object obj) {
		if (!CommonUtil.isBlank(obj)) {
			return getSuperClass(obj.getClass());
		}
		return null;
	}

	/**
	 * 获取接口
	 * 
	 * @param clazz
	 * @return
	 */
	public static Class[] getInterfaces(Class<?> clazz) {
		if (!CommonUtil.isBlank(clazz)) {
			return clazz.getInterfaces();
		}
		return null;
	}

	/**
	 * 获取接口
	 * 
	 * @param obj
	 * @return
	 */
	public static Class[] getInterfaces(Object obj) {
		if (!CommonUtil.isBlank(obj)) {
			return getInterfaces(obj.getClass());
		}
		return null;
	}

	/**
	 * 修改属性为可访问
	 * 
	 * @param field
	 */
	public static void makeAccessibleField(Field field) {
		if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
			field.setAccessible(true);
		}
	}

	/**
	 * 修改方法为可访问
	 * 
	 * @param method
	 */
	public static void makeAccessibleMethod(Method method) {
		if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) {
			method.setAccessible(true);
		}
	}

	/**
	 * 获取可访问的属性
	 * 
	 * @param obj
	 *            对象
	 * @param fieldName
	 *            属性
	 * @return
	 */
	public static Field getAccessibleField(Object obj, String fieldName) {
		if (!CommonUtil.isBlank(obj) && !CommonUtil.isBlank(fieldName)) {
			return getAccessibleField(obj.getClass(), fieldName);
		}
		return null;
	}

	/**
	 * 获取可访问的属性
	 * 
	 * @param clazz
	 *            类
	 * @param fieldName
	 *            属性
	 * @return
	 */
	public static Field getAccessibleField(Class clazz, String fieldName) {
		if (!CommonUtil.isBlank(clazz) && !CommonUtil.isBlank(fieldName)) {
			for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
				try {
					Field field = superClass.getDeclaredField(fieldName);
					makeAccessibleField(field);
					return field;
				} catch (NoSuchFieldException e) {// NOSONAR
					// Field不在当前类定义,继续向上转型
					continue;// new add
				}
			}
		}
		log.warn("{}属性找不到。", fieldName);
		return null;
	}

	/**
	 * 获取属性类型
	 * 
	 * @param clazz
	 * @param fieldName
	 * @return
	 */
	public static Class getAccessibleFieldType(Class clazz, String fieldName) {
		if (!CommonUtil.isBlank(clazz) && !CommonUtil.isBlank(fieldName)) {
			Field field = getAccessibleField(clazz, fieldName);
			if (!CommonUtil.isBlank(field)) {
				return field.getType();
			}
		}
		return null;
	}

	/**
	 * 获取属性类型
	 * 
	 * @param obj
	 * @param fieldName
	 * @return
	 */
	public static Class getAccessibleFieldType(Object obj, String fieldName) {
		if (!CommonUtil.isBlank(obj) && !CommonUtil.isBlank(fieldName)) {
			return getAccessibleFieldType(obj.getClass(), fieldName);
		}
		return null;
	}

	/**
	 * 获取可访问的方法
	 * 
	 * @param clazz
	 *            类
	 * @param methodName
	 *            方法名
	 * @param parameterTypes
	 *            参数类型
	 * @return
	 */
	public static Method getAccessibleMethod(Class clazz, String methodName, Class<?>... parameterTypes) {
		if (!CommonUtil.isBlank(clazz) && !CommonUtil.isBlank(methodName)) {
			for (Class<?> searchType = clazz; searchType != Object.class; searchType = searchType.getSuperclass()) {
				try {
					Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
					makeAccessibleMethod(method);
					return method;
				} catch (NoSuchMethodException e) {
					// Method不在当前类定义,继续向上转型
					continue;// new add
				}
			}
		}
		log.warn("{}方法找不到。", methodName);
		return null;
	}

	/**
	 * 获取可访问的方法
	 * 
	 * @param obj
	 *            对象
	 * @param methodName
	 *            方法名
	 * @param parameterTypes
	 *            参数类型
	 * @return
	 */
	public static Method getAccessibleMethod(Object obj, String methodName, Class<?>... parameterTypes) {
		if (!CommonUtil.isBlank(obj) && !CommonUtil.isBlank(methodName)) {
			return getAccessibleMethod(obj.getClass(), methodName, parameterTypes);
		}
		return null;
	}

	/**
	 * 设置属性的值
	 * 
	 * @param obj
	 * @param fieldName
	 * @param value
	 */
	public static void setFieldValue(Object obj, String fieldName, Object value) {
		if (!CommonUtil.isBlank(obj) && !CommonUtil.isBlank(fieldName) && !CommonUtil.isBlank(value)) {
			Field field = getAccessibleField(obj, fieldName);
			if (!CommonUtil.isBlank(field)) {
				try {
					field.set(obj, value);
				} catch (Exception e) {
					log.error("{}属性设置{}错误。", fieldName, value, e);
				}
			}
		}
	}

	/**
	 * 调用方法
	 * 
	 * @param obj
	 * @param methodName
	 * @param parameterTypes
	 * @param args
	 * @return
	 */
	public static Object invokeMethod(Object obj, String methodName, Class<?>[] parameterTypes, Object[] args) {
		if (!CommonUtil.isBlank(obj) && !CommonUtil.isBlank(methodName)) {
			Method method = getAccessibleMethod(obj, methodName, parameterTypes);
			if (!CommonUtil.isBlank(method)) {
				try {
					return method.invoke(obj, args);
				} catch (Exception e) {
					log.error("{}方法调用错误。", methodName, e);
				}
			}
		}
		return null;
	}

	/**
	 * 调用Getter方法. 支持多级，如：对象名.对象名.方法
	 */
	public static Object invokeGetter(Object obj, String fieldName) {
		if (!CommonUtil.isBlank(obj) && !CommonUtil.isBlank(fieldName)) {
			Object object = obj;
			for (String name : StringUtils.split(fieldName, ".")) {
				String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
				object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
			}
			return object;
		}
		return null;
	}

	/**
	 * 调用Setter方法, 仅匹配方法名。 支持多级，如：对象名.对象名.方法
	 */
	public static void invokeSetter(Object obj, String fieldName, Object value) {
		if (!CommonUtil.isBlank(obj) && !CommonUtil.isBlank(fieldName)) {
			Object object = obj;
			String[] names = StringUtils.split(fieldName, ".");
			for (int i = 0; i < names.length; i++) {
				if (i < names.length - 1) {
					String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
					object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
				} else {
					String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
					invokeMethod(object, setterMethodName, new Class[] { getAccessibleFieldType(object, fieldName) }, new Object[] { value });
				}
			}
		}
	}

	/**
	 * 获取所有属性
	 * 
	 * @param clazz
	 * @return
	 */
	public static List<Field> getAllFields(Class clazz) {
		if (!CommonUtil.isBlank(clazz)) {
			List<Field> fields = null;
			while (clazz != null) {
				if (CommonUtil.isBlank(fields)) {
					fields = new ArrayList<Field>();
				}
				fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
				clazz = getSuperClass(clazz);
			}
			return fields;
		}
		return null;
	}

	/**
	 * 获取所有属性
	 * 
	 * @param clazz
	 * @return
	 */
	public static List<Field> getAllFields(Object obj) {
		if (!CommonUtil.isBlank(obj)) {
			return getAllFields(obj.getClass());
		}
		return null;
	}

	/**
	 * 获取所有方法
	 * 
	 * @param clazz
	 * @return
	 */
	public static List<Method> getAllMethods(Class clazz) {
		if (!CommonUtil.isBlank(clazz)) {
			List<Method> methods = null;
			while (clazz != null) {
				if (CommonUtil.isBlank(methods)) {
					methods = new ArrayList<Method>();
				}
				methods.addAll(Arrays.asList(clazz.getDeclaredMethods()));
				clazz = getSuperClass(clazz);

			}
			return methods;
		}
		return null;
	}

	/**
	 * 获取所有方法
	 * 
	 * @param clazz
	 * @return
	 */
	public static List<Method> getAllMethods(Object obj) {
		if (!CommonUtil.isBlank(obj)) {
			return getAllMethods(obj.getClass());
		}
		return null;
	}

	/**
	 * 克隆
	 * 
	 * @param obj
	 * @return
	 */
	public static <T> T clone(Object obj, Class<T> clazz) {
		if (!CommonUtil.isBlank(obj)) {
			try {
				T t = clazz.newInstance();
				List<Field> fields = getAllFields(clazz);
				if (!CommonUtil.isBlank(fields)) {
					for (Field field : fields) {
						makeAccessibleField(field);
						field.set(t, field.get(obj));
					}
				}
				return t;
			} catch (Exception e) {
				log.error("{}创建失败，检查是否没有没参数构造函数。" + clazz.getName(), e);
			}
		}
		return null;
	}

	/**
	 * map转对象
	 * 
	 * @param obj
	 * @return
	 */
	public static <T> T MapToObject(Map<String, Object> map, Class<T> clazz) {
		if (!CommonUtil.isBlank(map)) {
			try {
				T t = clazz.newInstance();
				List<Field> fields = getAllFields(clazz);
				if (!CommonUtil.isBlank(fields)) {
					for (Field field : fields) {
						makeAccessibleField(field);
						field.set(t, map.get(field.getName()));
					}
				}
				return t;
			} catch (Exception e) {
				log.error("{}创建失败，检查是否没有没参数构造函数。" + clazz.getName(), e);
			}
		}
		return null;
	}

}